//交易场所
//线程间进行任务的交付
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;

    //version2
    static const int gacp = 10; //交易场所最大容量

    template <typename T> //交付不同的任务类型, 队列里存放的数据类型
    class BlockQueue
    {
    private:
        bool IsFull(){ return _q.size() == _cap; }
        bool IsEmpty(){ return _q.empty(); }
    public:
        BlockQueue(int cap = gacp)
        : _cap(cap),
         _cwait_num(0),
         _pwait_num(0)
        {}
        void Equeue(const T&in) //给生产者的函数调用
        {
            LockGuard lockguard(_mutex); //我们刚刚简化锁的使用创建的类, 加锁
            while(IsFull()) //对条件进行判断, 因为唤醒是在临界资源中唤醒, 防止伪唤醒
            {
                //如果为满就不能再放数据了
                std::cout << "生产者进入等待..." << std::endl;
                _pwait_num++;
                _productor_cond.wait(_mutex);
                _pwait_num--;
                std::cout << "生产者被唤醒..." << std::endl;
            }
            _q.push(in);
            //肯定有数据, 如果消费者等待队列中有等待的就唤醒他
            if(_cwait_num)
            {
                std::cout << "叫醒消费者" << std::endl;
                _consumer_cond.Notify();
            }
        }
        void Pop(T *out) //给消费者的函数调用
        {
            LockGuard lockguard(_mutex);
            while(IsEmpty())
            {
                //如果交易场所为空的情况下就不能再消费了
                std::cout << "消费者进入等待" << std::endl;
                _cwait_num++;
                _consumer_cond.wait(_mutex); //伪唤醒
                _cwait_num--;
                std::cout << "消费者被唤醒..." << std::endl; 
            }
            *out = _q.front(); //消费者取走数据
            _q.pop();
            //此时消费后有空间唤醒生产者
            if(_pwait_num)
            {
                std::cout << "叫醒生产者" << std::endl;
                _productor_cond.Notify();
            }
        }
        ~BlockQueue()
        {}
    private:
        std::queue<T> _q; //保存数据的容器, 保存临界资源
        int _cap; //bq最大的容量
        Mutex _mutex; //互斥锁
        Cond _productor_cond; //生产者条件变量
        Cond _consumer_cond; //消费者条件变量

        int _cwait_num; //消费者线程等待数量
        int _pwait_num; //生产者....
    };
}